home *** CD-ROM | disk | FTP | other *** search
/ Aminet 52 / Aminet 52 (2002)(GTI - Schatztruhe)[!][Dec 2002].iso / Aminet / misc / emu / Apex-src.lha / FLOPHANA.68K < prev    next >
Text File  |  2001-09-30  |  53KB  |  1,987 lines

  1. ;FLOPHANA.68K    JUN-15-88    (Also see INFOSTR)
  2. ;Amiga 3.5" Disk Handler
  3. ; by Loren Blaney
  4. ;
  5. ;REVISION HISTORY:
  6. ;MAR-11-87, Original
  7. ;JUN-15-88, Eliminate unnecessary delays waiting for motor spin up and
  8. ; initialize CIAB data direction register.
  9. ;
  10. ;WARNING:
  11. ;This currently works only for reading/writing an even number of blocks.
  12. ; The local variables should be in a stack structure, not at $D00.
  13. ;
  14. ;NOTES:
  15. ;This is based on a disassembly of the Amiga Kickstart "ROM" Kernel,
  16. ; V1.1, trackdisk.device 31.58 (23 Nov 1985).
  17. ;For further information see section 8.3 and Appendix A in the Amiga
  18. ; Hardware Manual, and see III-3 (Trackdisk) and Appendix L in the ROM
  19. ; Kernel Manual.
  20. ;
  21. ;The register convention used here is different than the convention
  22. ; generally used by Apex. The registers D0, D1, A0, and A1 are used
  23. ; as scratch. All other registers have their values preserved across
  24. ; subroutine calls.
  25. ;
  26. ;Apex blocks have 256 bytes; Amiga sectors have 512 bytes. "End
  27. ; buffering" is used to handle half sectors.
  28. ;
  29. ;INPUTS:
  30. ;    UNIT:    Unit number
  31. ;    FADDR:    Address in memory to read/write (long word)
  32. ;    BLKNOX:    Block on the disk to start read/write
  33. ;    NBLKS:    Number of blocks to read/write
  34. ;
  35. ;
  36. ;DISK FORMAT:
  37. ; Double sided, 80 cylinders, 160 tracks
  38. ;
  39. ;TRACK FORMAT:
  40. ; 11 sectors, gap
  41. ; (The gap is written as nulls. There are no gaps between sectors)
  42. ;
  43. ;SECTOR FORMAT:
  44. ; All data is MFM encoded (Amiga version).
  45. ; 0       00        (MFM = AAAA)
  46. ; 1       00        (MFM = AAAA)
  47. ; 2       A1        Standard sync byte -- MFM encoded $A1 with a
  48. ; 3       A1         clock pulse missing to distinguish it from
  49. ;             data (= $4489 each)
  50. ; 4      FF        Format byte (Amiga 1.0)
  51. ; 5      1 byte    Track number
  52. ; 6      1 byte    Sector number
  53. ; 7      1 byte    Number of sectors until end of write (1-11)
  54. ; 8     16 bytes     Header label -- OS recovery info (not used)
  55. ;24      4 bytes    Header "checksum" (bytes (4-23)
  56. ;28      4 bytes    Data "checksum"
  57. ;32    512 bytes    Data
  58. ;    (544 bytes total)
  59. ;
  60. ;"Checksums" are really just a simple exclusive-oring of the unencoded
  61. ; 16-bit words (i.e. parity check).
  62.  
  63.     NOLIST
  64.     INCLUDE    SYSPAG
  65.     LIST
  66.  
  67. ;----------------------------------------------------------------------
  68. ;DEFINITIONS:
  69. ;
  70. UNTNUM    EQU    0        ;Unit number of first floppy
  71.  
  72. CIAB    EQU    $BFD000        ;CIAB base address
  73. CIABB    EQU    $BFD100        ;CIAB PRB address (= CIAB + PRB)
  74.                 ;8520-A OUTPUTS:
  75.                 ;7 -DSKMOTOR    Motor on (latched)
  76.                 ;6 -DSKSEL3    Select drive 3
  77.                 ;5 -DSKSEL2    Select drive 2
  78.                 ;4 -DSKSEL1    Select drive 1
  79.                 ;3 -DSKSEL0    Select drive 0
  80.                 ;2 DSKSIDE    Select lower side
  81.                 ;1 DSKDIREC    Step outward (toward 0)
  82.                 ;0 -DSKSTEP    Step head
  83.  
  84. CIAA    EQU    $BFE001        ;Base address of 8520-A
  85.                 ; INPUTS:
  86.                 ;5 -DSKRDY    Disk is ready
  87.                 ;4 -DSKTRACK0    On track zero
  88.                 ;3 -DSKPROT    Write protected
  89.                 ;2 -DSKCHANGE    Disk was changed
  90.  
  91. DDRB    EQU    $300        ;Offset to CIA data direction register B
  92.  
  93. IOBASE    EQU    $DFF000        ;Base address of I/O
  94. DMACONR    EQU    $DFF002        ;DMA control register (read)
  95. INTREQR    EQU    $DFF01E        ;Interrupt request bits (read)
  96. DSKPTH    EQU    $DFF020        ;Pointer to disk buffer (high 3 bits)
  97. DSKPTL    EQU    $DFF022        ;Pointer to disk buffer (low 16 bits)
  98. DSKLEN    EQU    $DFF024        ;Number of words to transfer and
  99.                 ; bit 15 = DMA enable, bit 14 = write
  100. BLTCON0    EQU    $DFF040        ;Blitter control register 0
  101. BLTCON1    EQU    $DFF042        ;Blitter control register 1
  102. BLTAFWM    EQU    $DFF044        ;Blitter first word mask for source A
  103.  
  104. BLTBPTH    EQU    $DFF04C        ;Blitter pointer for source B
  105. BLTAPTH    EQU    $DFF050        ;Blitter pointer for source A
  106. BLTDPTH    EQU    $DFF054        ;Blitter pointer for source D
  107.  
  108. BLTSIZE    EQU    $DFF058        ;Blitter start and size register
  109. BLTBMOD    EQU    $DFF062        ;Blitter modulo for source B
  110.  
  111. INTENA    EQU    $DFF09A        ;Interrupt enable bits
  112. INTREQ    EQU    $DFF09C        ;Interrupt request bits
  113. ADKCON    EQU    $DFF09C        ;Audio, disk UART control
  114.  
  115. ;Register A1 points to a standard I/O request block whos format is:
  116. ;    IOStdReq    A1
  117. ;
  118. ;    Message        0    Not used
  119. ;    io_Device    20    Device/unit/drive number (0..3)
  120. ;    io_Unit        24    Pointer to local variables structure
  121. ;    io_Command    28    Read = 2; write = 3
  122. ;    io_Flags    30    Not used
  123. ;    io_Error    31    Error code (20..35)
  124. ;    io_Actual    32    Actual number of bytes read/written
  125. ;    io_Length    36    Requested number of bytes to read/write
  126. ;    io_Data        40    Pointer to memory data to read/write
  127. ;    io_Offset    44    Offset in bytes to track and sector
  128. ;
  129. ;    ioTD_Count    48    IOExtTD, For extended I/O which is not
  130. ;    ioTD_SecLabel    52     used here
  131. ;
  132. ;----------------------------------------------------------------------
  133. ;
  134.     ORG    $D00        ;*** THESE SHOULD NOT BE HERE *** ???
  135.  
  136. ;These variables have replaced the io_Unit structure:
  137. FLAGS    DS.B    1    ;38    ;Bit array
  138.                 ;0: Sector label in extended I/O is used
  139.                 ;1: No disk in drive
  140.                 ;2: Extended I/O is used
  141.                 ;3: (set and cleared but not used)
  142.                 ;4: Disk is write-protected (not used)
  143. CIABBX    DS.B    1    ;39    ;Copy of CIAB-B port
  144. CNTR    DS.B    1    ;40    ;Counter
  145.     DS.B    1
  146. IOPTR    DS.L    1    ;42    ;Pointer to IOStdReq structure
  147.     DS.B    1
  148. SECTOR    DS.B    1    ;47    ;Current sector number
  149. TRACKD    DS.W    1    ;48    ;Desired track number
  150.  
  151. ;GLOBAL VARIABLE:
  152. TRACKS    DS.W    4    ;50    ;Table of track numbers (for each unit)
  153. ;*** WARNING, THIS SHOULD BE INITIALIZED TO -1, OR THERE IS A SLIGHT
  154. ; CHANCE THAT A DISK WILL GET EATEN. ***
  155. TRACK    DS.W    1        ;Track number for current unit
  156.  
  157. PTR2    DS.L    1    ;58    ;Pointer into track buffer
  158. PTR1    DS.L    1    ;62    ;Pointer into track buffer
  159. IODATA    DS.L    1    ;66    ;Pointer to unencoded I/O data
  160. LBLBUF    DS.L    1    ;70    ;Pointer to sector label data region
  161.  
  162. SECBUF    DS.L    128        ;Sector buffer, blocks into sectors
  163.  
  164.     ORG    $70000        ;????????
  165. TRKBUF    DS.B    $4004        ;MFM Encoded track buffer
  166.  
  167. ;----------------------------------------------------------------------
  168. ;
  169.     ORG    MEMTOP - $2800
  170. START    EQU    @        ;Address where this handler starts
  171.  
  172. FLOPHAN    DC.L    DUMMY        ;0
  173.     DC.L    DUMMY        ;1
  174.     DC.L    READ        ;2
  175.     DC.L    WRITE        ;3
  176.     DC.L    DUMMY        ;4
  177.     DC.L    GETINFO        ;5
  178.     DC.L    DUMMY        ;6 (Spare)
  179.     DC.L    DUMMY        ;7 (Spare)
  180.  
  181. ;-----------------------------------------------------------------------
  182. ;Read bytes from floppy and store them into memory.
  183. ; This deals with the problem of reading 256-byte blocks from 512-byte
  184. ; sectors by doing "end buffering".
  185. ;
  186. READ    MOVEM.L    D0-D7/A0-A6,-(SP)    ;Save all registers
  187.  
  188.     BSR    OPEN        ;Initialize track buffer, etc.
  189.  
  190.     MOVE.L    BLKNOX,D2    ;Get arguments
  191.     MOVEA.L    FADDR,A2
  192.     MOVE.L    NBLKS,D3
  193.  
  194.     BTST    #0,D2        ;Is BLKNOX an odd number?
  195.     BEQ.S    RD20        ;Branch if not
  196.     SUBQ.L    #1,D2        ;Backup to previous (even) block
  197.     LEA    SECBUF,A2    ;Read 2 blocks into the sector buffer
  198.     MOVEQ    #2,D3
  199.     BSR    DOREAD        ;READ(BLKNOX, FADDR, NBLKS)
  200.                 ;    D2    A2    D3
  201.  
  202.     LEA    SECBUF,A0    ;Move the second block in the sector
  203.     LEA    $100(A0),A0    ; buffer into memory at FADDR
  204.     MOVEA.L    FADDR,A2
  205.     MOVEQ    #64-1,D0
  206. RD10    MOVE.L    (A0)+,(A2)+    ;Do it 4 bytes at a time
  207.     DBF    D0,RD10
  208.  
  209.                 ;(A2  [FADDR] is incremented by 256)
  210.     ADDQ.L    #2,D2        ;Net gain of one block (BLKNOX)
  211.     MOVE.L    NBLKS,D3    ;One less block to do
  212.     SUBQ.L    #1,D3
  213. RD20
  214.     MOVEQ    #FALSE,D4    ;Anticipate an even number of remaining
  215.     BTST    #0,D3        ; blocks
  216.     BEQ.S    RD30        ;Branch if correct
  217.     MOVEQ    #TRUE,D4    ;Set flag to handle last, odd block
  218.     SUBQ.L    #1,D3        ;Decrement NBLKS to make them even
  219.     MOVE.L    D3,D0        ;FADDR' := FADDR + NBLKS *256
  220.     ASL.L    #8,D0        ; A3      A2      D3
  221.     LEA    0(A2,D0.L),A3
  222. RD30
  223.     TST.L    D3        ;Are there some blocks to read?
  224.     BEQ.S    RD40        ;Branch if not
  225.     BSR    DOREAD        ;READ(BLKNOX, FADDR, NBLKS)
  226. RD40                ;    D2    A2    D3
  227.     TST.W    D4        ;Is there a last, odd block?
  228.     BEQ.S    RD60        ;Branch if not
  229.     LEA    SECBUF,A2    ;Read 2 blocks into the sector buffer
  230.     ADD.L    D3,D2        ;BLKNOX:= BLKNOX + NBLKS 
  231.     MOVEQ    #2,D3
  232.     BSR    DOREAD        ;READ(BLKNOX, FADDR, NBLKS)
  233.                 ;    D2    A2    D3
  234.     LEA    SECBUF,A0    ;Move the first block in the sector
  235.     MOVEQ    #64-1,D0    ; buffer into memory (FADDR')
  236. RD50    MOVE.L    (A0)+,(A3)+    ;Do it 4 bytes at a time
  237.     DBF    D0,RD50
  238. RD60
  239.     BSR    MTROFF        ;Turn off the motor
  240.  
  241.     MOVEM.L    (SP)+,D0-D7/A0-A6    ;Restore all registers
  242. DUMMY    RTS
  243.  
  244. ;-----------------------------------------------------------------------
  245. ;Write bytes from memory onto the floppy.
  246. ; This deals with the problem of writing 256-byte blocks on to 512-byte
  247. ; sectors by doing "end buffering".
  248. ;
  249. WRITE    MOVEM.L    D0-D7/A0-A6,-(SP)    ;Save all registers
  250.  
  251.     BSR    OPEN        ;Initialize track buffer, etc.
  252.  
  253.     MOVE.L    BLKNOX,D2    ;Get arguments
  254.     MOVEA.L    FADDR,A2
  255.     MOVE.L    NBLKS,D3
  256.  
  257.     BTST    #0,D2        ;Is BLKNOX an odd number?
  258.     BEQ.S    WR20        ;Branch if not
  259.     SUBQ.L    #1,D2        ;Backup to previous (even) block
  260.     LEA    SECBUF,A2    ;Read 2 blocks into the sector buffer
  261.     MOVEQ    #2,D3
  262.     BSR    DOREAD        ;READ(BLKNOX, FADDR, NBLKS)
  263.                 ;    D2    A2    D3
  264.  
  265.     MOVEA.L    FADDR,A0
  266.     LEA    SECBUF,A1    ;Move memory (at FADDR) into the second
  267.     LEA    $100(A1),A1    ; block in the sector buffer
  268.     MOVEQ    #64-1,D0    ;Move 64 longs
  269. WR10    MOVE.L    (A0)+,(A1)+    ;Do it 4 bytes at a time
  270.     DBF    D0,WR10
  271.  
  272.     BSR    DOWRITE        ;WRITE(BLKNOX, FADDR, NBLKS)
  273.                 ;    D2    A2    D3
  274.     MOVEA.L    A0,A2        ;(A2  [FADDR] is incremented by 256)
  275.     ADDQ.L    #2,D2        ;Net gain of one block (BLKNOX)
  276.     MOVE.L    NBLKS,D3    ;One less block to do
  277.     SUBQ.L    #1,D3
  278. WR20
  279.     MOVEQ    #FALSE,D4    ;Anticipate an even number of remaining
  280.     BTST    #0,D3        ; blocks
  281.     BEQ.S    WR30        ;Branch if correct
  282.     MOVEQ    #TRUE,D4    ;Set flag to handle last, odd block
  283.     SUBQ.L    #1,D3        ;Decrement NBLKS to make them even
  284.     MOVE.L    D3,D0        ;FADDR' := FADDR + NBLKS *256
  285.     ASL.L    #8,D0        ; A3      A2      D3
  286.     LEA    0(A2,D0.L),A3
  287. WR30
  288.     TST.L    D3        ;Are there some blocks to WRITE?
  289.     BEQ.S    WR40        ;Branch if not
  290.     BSR    DOWRITE        ;WRITE(BLKNOX, FADDR, NBLKS)
  291. WR40                ;    D2    A2    D3
  292.     TST.W    D4        ;Is there a last, odd block?
  293.     BEQ.S    WR60        ;Branch if not
  294.     LEA    SECBUF,A2    ;Read 2 blocks into the sector buffer
  295.     ADD.L    D3,D2        ;BLKNOX:= BLKNOX + NBLKS 
  296.     MOVEQ    #2,D3
  297.     BSR    DOREAD        ;READ(BLKNOX, FADDR, NBLKS)
  298.                 ;    D2    A2    D3
  299.     MOVEA.L    A3,A0
  300.     LEA    SECBUF,A1    ;Move 256 bytes from memory (at FADDR')
  301.     MOVEQ    #64-1,D0    ; into the first half of the sector buf
  302. WR50    MOVE.L    (A0)+,(A1)+    ;Do it 4 bytes at a time
  303.     DBF    D0,WR50
  304.  
  305.     BSR    DOWRITE        ;WRITE(BLKNOX, FADDR, NBLKS)
  306. WR60                ;    D2    A2    D3
  307.     BSR    CLOSE        ;Write anything left in the track buffer
  308.  
  309.     MOVEM.L    (SP)+,D0-D7/A0-A6    ;Restore all registers
  310.     RTS
  311.  
  312. ;-----------------------------------------------------------------------
  313. ;Return the address of the information block in D0
  314. ;
  315. GETINFO    MOVE.L    #INFO,D0
  316.     RTS
  317.  
  318. INFO    DC.L    START        ;Handler start and end addresses
  319.     DC.L    END
  320.     DC.L    INFOSTR
  321. INFOSTR    ASCII    'FLOPHANA  JUN-15-88  3 1/2", 3520 blocks'
  322.     DC.B    0
  323.  
  324. ;======================================================================
  325. ;SUBROUTINES
  326. ;-----------------------------------------------------------------------
  327. ;Read bytes from floppy and store them into memory.
  328. ;
  329. ; Inputs:
  330. ;    D2 = (BLKNOX_) Starting Apex block number (must be even)
  331. ;    A2 = (FADDR_) Starting memory address to read/write
  332. ;    D3 = (NBLKS_) Number of Apex blocks (must be even)
  333. ;
  334. DOREAD    MOVEM.L    D0-D7/A0-A6,-(SP)    ;Save registers
  335.  
  336.     LINK    A5,#-56        ;Reserve space for IOStdReq structure
  337.     MOVEA.L    SP,A1        ;Point to base of IOStdReq structure
  338.     BSR    SETUP        ;Initialize IOStdReq structure
  339.  
  340.     MOVE.W    #2,28(A1)    ;Indicate "read"
  341.     BSR    CMD_RW        ;Call disk I/O handler
  342.  
  343.     BSR    REPORT        ;Report any errors
  344.  
  345.     UNLK    A5        ;Release structure space
  346.     MOVEM.L    (SP)+,D0-D7/A0-A6    ;Restore registers
  347.     RTS
  348.  
  349. ;-----------------------------------------------------------------------
  350. ;Write bytes from memory onto the floppy
  351. ;
  352. ; Inputs:
  353. ;    D2 = (BLKNOX_) Starting Apex block number (must be even)
  354. ;    A2 = (FADDR_) Starting memory address to read/write
  355. ;    D3 = (NBLKS_) Number of Apex blocks (must be even)
  356. ;
  357. DOWRITE    MOVEM.L    D0-D7/A0-A6,-(SP)    ;Save registers
  358.  
  359.     LINK    A5,#-56        ;Reserve space for IOStdReq structure
  360.     MOVEA.L    SP,A1        ;Point to base of IOStdReq structure
  361.     BSR    SETUP        ;Initialize IOStdReq structure
  362.  
  363.     MOVE.W    #3,28(A1)    ;Indicate "write"
  364.     BSR    CMD_RW        ;Call disk I/O handler
  365.  
  366.     BSR    REPORT        ;Report any errors
  367.  
  368.     UNLK    A5        ;Release structure space
  369.     MOVEM.L    (SP)+,D0-D7/A0-A6    ;Restore registers
  370.     RTS
  371.  
  372. ;----------------------------------------------------------------------
  373. ;Routine to set up the IOStdReq structure.
  374. ; Inputs:
  375. ;    A1 = Pointer to IOStdReq structure
  376. ;    D2 = (BLKNOX_) Starting Apex block number (must be even)
  377. ;    A2 = (FADDR_) Starting memory address to read/write
  378. ;    D3 = (NBLKS_) Number of Apex blocks (must be even)
  379. ;
  380. ; Outputs:
  381. ;    PTR = Pointer to encoded track buffer
  382. ;    FLAGS
  383. ;
  384. ;Registers D0, D1 and A0 are destroyed.
  385. ;
  386. SETUP    MOVE.W    #$8250,$DFF096.L    ;Enable blitter and disk DMA
  387.     MOVE.W    #$0400,$DFF09E.L    ;Clear WORDSYNC
  388.     MOVE.W    #$8100,$DFF09E.L    ;Enable fast mode
  389.  
  390.     MOVE.B    #0,FLAGS
  391.  
  392.     MOVEA.L    A1,A0
  393.     MOVEQ    #55,D0        ;Clear the structure space
  394. SUP10    CLR.B    (A0)+
  395.     DBF    D0,SUP10
  396.  
  397.     MOVE.B    UNIT,D0        ;Get unit number, 0..3
  398.     ANDI.B    #$03,D0
  399.     MOVE.B    D0,23(A1)    ;io_Device
  400.  
  401.     MOVE.L    D3,D0        ;Number of bytes = NBLKS_ * 256
  402.     ASL.L    #8,D0
  403.     MOVE.L    D0,36(A1)    ;io_Length
  404.  
  405.     MOVE.L    A2,40(A1)    ;io_Data
  406.  
  407.     MOVE.L    D2,D0        ;Offset = BLKNOX_ * 256
  408.     ASL.L    #8,D0
  409.     MOVE.L    D0,44(A1)    ;io_Offset
  410.  
  411.     RTS
  412.  
  413. ;----------------------------------------------------------------------
  414. ;This routine initializes the track buffer and sets PTR1 to it.
  415. ; Registers D0, D1, and A0 are destroyed.
  416. ;
  417. OPEN    LEA    CIAB.L,A0    ;Point to base of 8520-B
  418.     MOVE.B    #$FF,DDRB(A0)    ;Set port B to all outputs
  419.  
  420.     MOVE.B    #$FF,CIABBX    ;Indicate that motor is off (bit 7 high)
  421.  
  422.     LEA    TRKBUF.L,A0    ;Track buffer ($4004 bytes)
  423.     MOVE.L    A0,PTR1
  424.     MOVE.W    #-1,0(A0)    ;Set invalid track number
  425.     MOVE.W    #0,2(A0)    ;Indicate "clean" buffer
  426.  
  427.     MOVE.L    #$AAAAAAAA,D1    ;Fill track buffer with clock bits
  428.     MOVE.W    #$FFF,D0
  429.     LEA    4(A0),A0
  430. OP05    MOVE.L    D1,(A0)+
  431.     DBF    D0,OP05
  432.  
  433.     RTS
  434.  
  435. ;----------------------------------------------------------------------
  436. ;This routine writes the track buffer to disk if there is something
  437. ; on it.
  438. ;
  439. CLOSE    LEA    TRKBUF.L,A0    ;Is the track buffer dirty?
  440.     BTST    #0,2(A0)
  441.     BEQ.S    CL20        ;Branch if not
  442.     MOVE.L    A0,PTR2
  443.     BSR    SUBRO        ;Write the track buffer (D0=error code)
  444. CL20
  445.     BSR    REPORT        ;Report any error
  446.     BRA    MTROFF        ;(PBRA) Turn off the motor
  447.  
  448. ;-----------------------------------------------------------------------
  449. ;Report the error for the error code in D0.
  450. ; D0 and A6 are destroyed.
  451. ;
  452. REPORT    TST.B    D0        ;Test the error code
  453.     BEQ    ERR00        ;Branch if no errors
  454.  
  455.     BSR    MTROFF        ;Turn off the motor
  456.     CMPI.B    #20,D0        ;It's an unspecified error if the error
  457.     BLO    ERR20        ; code is outside the range 20..35
  458.     CMPI.B    #35,D0
  459.     BHI    ERR20
  460.  
  461.     SUBI.B    #20,D0        ;Subtract offset
  462.     LSL.W    #2,D0        ;Times 4 for long entries
  463.     MOVEA.W    D0,A6        ;Move index into an address register
  464.     LEA    ERRTBL-@-2(PC,A6),A6 ;Get the address of the table entry
  465.     MOVEA.L    (A6),A6        ;Get the address of the error routine
  466.     JMP    (A6)        ;Jump to this address
  467.  
  468. ;Table of entry points to error reporting routines
  469. ERRTBL    DC.L    ERR20
  470.     DC.L    ERR21
  471.     DC.L    ERR22
  472.     DC.L    ERR23
  473.     DC.L    ERR24
  474.     DC.L    ERR25
  475.     DC.L    ERR26
  476.     DC.L    ERR27
  477.     DC.L    ERR28
  478.     DC.L    ERR29
  479.     DC.L    ERR30
  480.     DC.L    ERR31
  481.     DC.L    ERR32
  482.     DC.L    ERR33
  483.     DC.L    ERR34
  484.     DC.L    ERR35
  485.  
  486. ;-----------------------------------------------------------------------
  487. ;ERROR REPORTING ROUTINES
  488. ;
  489. ; Normal errors include:
  490. ;    door open
  491. ;    write protected
  492. ;    damaged disk
  493. ;    unformatted disk
  494. ;    wrong format
  495. ;    inserted wrong
  496. ;
  497. ERR20    JSR    VERROR
  498.     ASCII    '20 - DISK ERROR (UNSPECIFIED)'
  499.     DC.B    0
  500. ERR00    RTS            ;(PJMPs won't work)
  501.  
  502. ERR21    JSR    VERROR
  503.     ASCII    '21 - NO SECTOR HEADER'
  504.     DC.B    0
  505.     RTS
  506.  
  507. ERR22    JSR    VERROR
  508.     ASCII    '22 - SECTOR PREAMBLE'
  509.     DC.B    0
  510.     RTS
  511.  
  512. ERR23    JSR    VERROR
  513.     ASCII    '23 - SECTOR ID'
  514.     DC.B    0
  515.     RTS
  516.  
  517. ERR24    JSR    VERROR
  518.     ASCII    '24 - HEADER CHECKSUM'
  519.     DC.B    0
  520.     RTS
  521.  
  522. ERR25    JSR    VERROR
  523.     ASCII    '25 - DATA CHECKSUM'
  524.     DC.B    0
  525.     RTS
  526.  
  527. ERR26    JSR    VERROR
  528.     ASCII    '26 - TOO FEW SECTORS'
  529.     DC.B    0
  530.     RTS
  531.  
  532. ERR27    JSR    VERROR
  533.     ASCII    '27 - SECTOR HEADER'
  534.     DC.B    0
  535.     RTS
  536.  
  537. ERR28    JSR    VERROR
  538.     ASCII    '28 - WRITE PROTECTED'
  539.     DC.B    0
  540.     RTS
  541.  
  542. ERR29    JSR    VERROR
  543.     ASCII    '29 - DISK CHANGED OR MISSING'
  544.     DC.B    0
  545.     RTS
  546.  
  547. ERR30    JSR    VERROR
  548.     ASCII    '30 - SEEK'
  549.     DC.B    0
  550.     RTS
  551.  
  552. ERR31    JSR    VERROR
  553.     ASCII    '31 - DISK MEMORY OVERFLOW'
  554.     DC.B    0
  555.     RTS
  556.  
  557. ERR32    JSR    VERROR
  558.     ASCII    '32 - DISK UNIT NUMBER'
  559.     DC.B    0
  560.     RTS
  561.  
  562. ERR33    JSR    VERROR
  563.     ASCII    '33 - DRIVE TYPE'
  564.     DC.B    0
  565.     RTS
  566.  
  567. ERR34    JSR    VERROR
  568.     ASCII    '34 - DISK IN USE'
  569.     DC.B    0
  570.     RTS
  571.  
  572. ERR35    JSR    VERROR
  573.     ASCII    '35 - DISK - UNASSIGNED'
  574.     DC.B    0
  575.     RTS
  576.  
  577. ;----------------------------------------------------------------------
  578. ;This routine turns off the motor for the current unit.
  579. ;
  580. MTROFF    MOVE.L    D0,-(SP)    ;Save D0
  581.  
  582.     MOVE.B    #$FF,CIABBX    ;Turn off the motor
  583.     MOVE.B    CIABBX,CIABB.L    ; (this also selects the lower head)
  584.     MOVEQ    #3,D0        ;Select units 0..3 which correspond to
  585.     ADD.B    UNIT,D0        ; bits 3..6
  586.     BCLR    D0,CIABBX
  587.     MOVE.B    CIABBX,CIABB.L
  588.     BSET    D0,CIABBX    ;Deselect unit
  589.     MOVE.B    CIABBX,CIABB.L
  590.     MOVE.L    (SP)+,D0    ;Restore D0
  591.     RTS
  592.  
  593. ;======================================================================
  594. ;FLOPPY DISK ROUTINES MODIFIED FROM ROM KERNEL CODE:
  595. ;----------------------------------------------------------------------
  596. ;Read or write I/O data from or to the disk.
  597. ;
  598. ;Inputs:
  599. ;    A1    = IOStdReq (the significant entries are shown):
  600. ;        io_Command = 2=Read, 3=Write
  601. ;        io_Length = Number of bytes to read/write (must be an
  602. ;            integer multiple of 256)
  603. ;        io_Data = Pointer to (unencoded) I/O data
  604. ;        io_Offset = Byte address of disk location (= sector *
  605. ;            cylinder * 2 * 512)
  606. ;    PTR1    = Pointer to track buffer
  607. ;    TRACKS    = Array of current head positons for each unit
  608. ;
  609. ;Outputs:
  610. ;    D0 = Error code
  611. ;
  612. ;
  613. CMD_RW    MOVEM.L    D2/A2-A4,-(SP)    ;Save registers
  614.  
  615.     MOVEA.L    24(A1),A3    ;Get io_Unit structure (this has been
  616.     MOVEA.L    A1,A2        ; replaced by variable names)
  617.     MOVE.L    A2,IOPTR    ;Save pointer to IOStdReq structure
  618.  
  619. ;Set port control bits (CIABBX) and TRACK for current unit:
  620.     MOVE.B    CIABBX,D0    ;Select drive (= unit = device)
  621.     ORI.B    #$7F,D0        ;Disable all bits except DSKMOTOR
  622.     MOVE.W    22(A2),D1    ;Get io_Device (unit)
  623.     ANDI.W    #$0003,D1    ;Mask for safety, legal units: 0..3
  624.     MOVE.L    D1,D2        ;Save copy of unit number
  625.     ADDI.W    #$0003,D1    ;CIABB bits 3..6 select units 0..3
  626.     BCLR    D1,D0        ;Drive select is true low
  627.  
  628.     ADD.W    D2,D2        ;Get track for current unit
  629.     LEA    TRACKS.L,A0    ;Index into TRACK table (words)
  630.     MOVE.W    0(A0,D2.W),D1
  631.     MOVE.W    D1,TRACK    ;Set track number for current unit
  632.     BTST    #0,D1        ;Is this an odd or even track number?
  633.     BEQ.S    LB300        ;Branch if even -- use lower side
  634.     BCLR    #2,D0        ;Else, select upper head
  635. LB300
  636.     MOVE.B    D0,CIABBX    ;Set copy of CIA-B port
  637.  
  638.     MOVE.L    #0,32(A2)    ;Clear io_Actual (amount read/written)
  639.     MOVE.L    40(A2),IODATA    ;Get pointer to io_Data
  640.     MOVE.L    44(A2),D0    ;Get io_Offset
  641.     MOVE.L    D0,D1
  642.     ANDI.L    #$000001FF,D1    ;Must be an integer multiple of 512
  643.     BNE    LB50A        ;Branch if not
  644.     CMPI.L    #$000DC000,D0    ;Must be < 2 *80 *11 *512
  645.     BHS    LB50A        ;Branch if not
  646.     MOVE.L    36(A2),D1    ;Get io_Length
  647.     ADD.L    D0,D1        ;Add io_Offset
  648.     CMPI.L    #$000DC000,D1    ;Must be <= 2 *80 *11 *512
  649.     BHI    LB50A        ;Branch if not
  650.     MOVEQ    #9,D1        ;Divide by 512 to get "sector" number
  651.     LSR.L    D1,D0
  652.     DIVU    #11,D0        ;Divide by 11 to get desired track no.
  653.     MOVE.W    D0,TRACKD
  654.     SWAP    D0        ;Get the remainder, the sector number
  655.     MOVE.B    D0,SECTOR
  656.  
  657.     BTST    #2,FLAGS    ;Is extended I/O used?
  658.     BEQ.S    LB36E        ;Branch if not
  659.  
  660.     MOVE.L    52(A2),LBLBUF    ;Get pointer to sector label
  661.     BEQ.S    LB36E        ;Branch if it is not used
  662.     BSET    #0,FLAGS    ;Indicate sector label is not used
  663. LB36E
  664.     BTST    #1,FLAGS    ;Is there a disk inserted?
  665.     BEQ.S    LB380        ;Branch if yes
  666.     MOVE.B    #29,31(A2)    ;io_Error: Disk changed or not present
  667.     BRA    LB500        ;Exit
  668. LB380
  669.     MOVE.W    TRACKD,D0    ;Get the desired track number
  670.     BSR    SUBRM        ;Is this track in the buffer?
  671.     MOVE.L    A0,PTR2        ;Set PTR2=A0 if not
  672.     BNE.S    LB3E4        ;Branch if it is in the buffer
  673.  
  674.     MOVEA.L    PTR1,A0
  675.     MOVEA.L    A0,A2
  676.     MOVE.L    A2,PTR2        ;PTR2:= A2:= A0:= PTR1
  677.  
  678. ;Read track into buffer, loop for all tracks:
  679. LB398    BTST    #0,2(A2)    ;Is the current track "dirty"
  680.     BEQ.S    LB3B4        ;Branch if not
  681.     BSR    SUBRO        ;Write the current track
  682.     TST.L    D0        ;Any errors?
  683.     BEQ.S    LB3B4        ;Branch if not
  684.     MOVEA.L    IOPTR,A1
  685.     MOVE.B    D0,31(A1)    ;Set io_Error
  686.     BRA    LB500        ;Exit
  687. LB3B4
  688.     MOVE.W    TRACKD,0(A2)    ;Get desired track number
  689.     BCLR    #0,2(A2)
  690.     CLR.B    CNTR        ;Initialize counter
  691.     BSR    SUBRP        ;Read in the desired track
  692.  
  693.  
  694.     MOVE.B    3(A2),D0
  695.     CMPI.B    #11,D0        ;Any bad errors?
  696.     BLO.S    LB3E4        ;Branch if not
  697.     MOVE.W    #$FFFF,0(A2)
  698.     MOVEA.L    IOPTR,A1
  699.     MOVE.B    D0,31(A1)    ;Set io_Error
  700.     BRA    LB500        ;Exit
  701.  
  702. ;Track is in the buffer, loop for all sectors:
  703. LB3E4    MOVEA.L    IOPTR,A2    ;Get io_StdReq
  704.     MOVE.W    28(A2),D0    ;Get I/O command
  705.     MOVEA.L    PTR2,A0
  706.     CMPI.B    #$03,D0        ;Is it a write command?
  707.     BNE    LB470        ;Branch if not (must be read)
  708.  
  709. ;Write command:
  710.     BSET    #0,2(A0)
  711.     MOVEQ    #0,D0        ;Calculate offset into the track
  712.     MOVE.B    SECTOR,D0    ; buffer to the desired sector
  713.     SUB.B    3(A0),D0
  714.     BPL.S    LB40E
  715.     ADDI.B    #11,D0
  716. LB40E
  717.     MULU    #544*2,D0    ;Multiply by encoded bytes per sector
  718.     LEA    1664(A0),A4    ;Skip the gap
  719.     ADDA.L    D0,A4
  720.     BTST    #0,FLAGS    ;Is sector label (header) used?
  721.     BEQ.S    LB446        ;Branch if not
  722.     MOVEA.L    LBLBUF,A0    ;Point to label (header) data
  723.     MOVE.L    #16,D0        ;Encode 16 bytes
  724.     LEA    16(A4),A1    ;A1 = location for encoded data
  725.     BSR    ENCODE        ;Encode and move the label data
  726.  
  727.     LEA    8(A4),A0    ;Point to encoded data
  728.     MOVE.W    #40,D1        ;Number of encoded bytes
  729.     BSR    DOCKSUM        ;Compute header checksum (D0)
  730.  
  731.     LEA    48(A4),A0    ;Encode and store header checksum
  732.     BSR    ENCOD_L
  733.  
  734. LB446    MOVEA.L    IODATA,A0    ;Get pointer to io_Data
  735.     MOVE.L    #512,D0        ;Number of bytes to encode
  736.     LEA    64(A4),A1    ;A1 = location for encoded data
  737.     BSR    ENCODE        ;Encode and move sector data
  738.  
  739.     LEA    64(A4),A0    ;Point to start of encoded data
  740.     MOVE.W    #1024,D1    ;Number of bytes of encoded data
  741.     BSR    DOCKSUM        ;Compute checksum (D0)
  742.  
  743.     LEA    56(A4),A0    ;Encode and store data checksum
  744.     BSR    ENCOD_L
  745.     BRA    LB4B6        ;Go to next sector
  746.  
  747. ;Enter here if read command:
  748. LB470    MOVEQ    #0,D0        ;sector number (0..10)
  749.     MOVE.B    SECTOR,D0
  750.     SUB.B    3(A0),D0
  751.     BPL.S    LB480
  752.     ADDI.B    #11,D0
  753. LB480
  754.     MULU    #544*2,D0    ;calculate offset into track buffer
  755.     LEA    1664(A0),A4    ; to desired sector
  756.     ADDA.L    D0,A4
  757.     BTST    #0,FLAGS    ;Is extended I/O (header) used?
  758.     BEQ.S    LB4A4        ;Branch if not
  759.     LEA    16(A4),A1    ;Point to encoded label (header) data
  760.     MOVEA.L    LBLBUF,A0    ;Point to place for decoded label data
  761.     MOVE.L    #16,D0        ;Number of bytes to decode
  762.     BSR    DECODE        ;Decode and move a block of data
  763. LB4A4
  764.     LEA    64(A4),A1    ;Point to encoded data
  765.     MOVEA.L    IODATA,A0    ;Get pointer to io_Data (destination)
  766.     MOVE.L    #512,D0        ;Number of bytes to decode
  767.     BSR    DECODE        ;Decode and move a block of data
  768.  
  769. LB4B6    MOVE.L    #512,D1        ;Point to next sector
  770.     ADD.L    D1,IODATA
  771.     MOVE.L    32(A2),D0    ;Bump io_Actual
  772.     ADD.L    D1,D0
  773.     MOVE.L    D0,32(A2)
  774.     BTST    #0,FLAGS    ;Is extended I/O used?
  775.     BEQ.S    LB4DA        ;Branch if not
  776.     ADDI.L    #16,LBLBUF    ;Bump label pointer
  777. LB4DA
  778.     CMP.L    36(A2),D0    ;Compare io_Actual to io_Length
  779.     BHS.S    LB500        ;Branch if we're done -- exit
  780.     MOVEA.L    PTR2,A2
  781.     ADDQ.B    #1,SECTOR    ;Next sector
  782.     CMPI.B    #11,SECTOR    ;Are we in the next track?
  783.     BLT    LB3E4        ;Branch if not -- loop back
  784.  
  785.     MOVE.B    #0,SECTOR    ;Start next track with sector 0
  786.     ADDQ.W    #1,TRACKD    ;Next track
  787.     BRA    LB398        ;Loop until all sectors are copied
  788.  
  789. LB500    MOVEA.L    IOPTR,A1
  790.     BRA.S    LB516        ;Exit
  791.  
  792. LB50A    MOVEA.L    IOPTR,A1
  793.     MOVE.B    #$FF,31(A1)    ;Set io_Error (-1)
  794.     BRA.S    LB500        ;Exit (circuitously)
  795.  
  796. LB516    MOVEA.L    IOPTR,A1    ;Record current track in TRACKS array
  797.     MOVE.W    22(A1),D2    ;Get io_Device (unit)
  798.     ANDI.W    #$0003,D2    ;Mask for safety, legal units: 0..3
  799.     ADD.W    D2,D2
  800.     LEA    TRACKS.L,A0    ;Index into TRACK table (words)
  801.     MOVE.W    TRACK,0(A0,D2.W) ;Set track number for current unit
  802.  
  803.     MOVEQ    #0,D0        ;Return error code in D0
  804.     MOVE.B    31(A1),D0
  805.  
  806.     MOVEM.L    (SP)+,D2/A2-A4    ;Restore registers
  807.     RTS
  808.  
  809. ;----------------------------------------------------------------------
  810. ;If the track number (D0) is written in the buffer, then A0 is returned
  811. ; set equal to PTR1.
  812. ; Inputs: track number (D0) and PTR1.
  813. ;
  814. SUBRM    MOVE.L    PTR1,D1        ;Get pointer
  815.     TST.L    D1        ;Branch if it is zero
  816.     BEQ.S    SUBRM10
  817.  
  818.     MOVEA.L    D1,A0        ;Is the track number in the buffer?
  819.     CMP.W    0(A0),D0    ;Return A0 = PTR1
  820.     BEQ.S    SUBRM99
  821. SUBRM10    MOVEQ    #0,D0        ;Return D0 = A0 = 0
  822.     MOVEA.L    D0,A0
  823. SUBRM99    RTS
  824.  
  825. ;----------------------------------------------------------------------
  826. ;Routine to write a track.
  827. ; Inputs:
  828. ;    PTR2 = Pointer to encoded buffer
  829. ;        0 = track number
  830. ;        2 = bit #0 = dirty/clean flag
  831. ;        4 = actual buffer space begins here
  832. ;
  833. SUBRO    MOVEM.L    D2/A2,-(SP)
  834.  
  835.     MOVEA.L    PTR2,A2
  836.  
  837.     MOVEQ    #1,D0        ;Turn on the motor
  838.     BSR    DOMOTOR
  839.  
  840.     MOVEQ    #0,D0
  841.     MOVE.W    0(A2),D0    ;Move to track recorded in buffer
  842.     BSR    DOSEEK
  843.  
  844.     LEA    4(A2),A0    ;Location of buffer
  845.     MOVE.W    #13630,D0    ;Write 13630 encoded bytes to a track
  846.     BSR    WRITTRK        ; (13630 = 544 *2 *11 + 1662)
  847.  
  848.     MOVEM.L    (SP)+,D2/A2
  849.     RTS
  850.  
  851. ;----------------------------------------------------------------------
  852. ;Routine to read a track
  853. ; Inputs PTR2 = Pointer to buffer
  854. ;
  855. SUBRP    MOVEM.L    A2,-(SP)    ;Save A2
  856.  
  857.     MOVEA.L    PTR2,A2        ;Point to buffer for encoded data
  858.  
  859.     MOVEQ    #1,D0        ;Turn on the motor
  860.     BSR    DOMOTOR
  861.  
  862. SUBRP10    MOVEQ    #0,D0
  863.     MOVE.W    TRACKD,D0    ;Move head to desired track
  864.     BSR    DOSEEK
  865.  
  866. SUBRP20    LEA    $4000-14716(A2),A0    ;Fill bottom of 16K buffer
  867.     MOVE.W    #14716,D0    ;Number of encoded bytes to read
  868.  
  869.     BSR    READTRK        ;Read a track
  870.  
  871.     TST.L    D0        ;Was there an error?
  872.     BEQ.S    SUBRP30        ;Branch if not
  873.     MOVE.B    D0,3(A2)
  874.     BRA    SUBRP90        ;Exit
  875. SUBRP30
  876.     BSR    SUBRXQ        ;Verify header and checksum
  877.     MOVE.B    D0,3(A2)    ;Save error code
  878.     CMPI.B    #11,D0
  879.     BLO.S    SUBRP90        ;Exit on certain errors
  880.  
  881.     ADDQ.B    #1,CNTR        ;Bump sector counter
  882.     MOVE.B    CNTR,D0
  883.     CMPI.B    #10,D0        ;Are all 11 sectors read in?
  884.     BGT.S    SUBRP90        ;Branch if yes -- exit
  885.  
  886.     ANDI.B    #$03,D0
  887.     BNE.S    SUBRP20        ;Loop for 11 sectors
  888.  
  889.     MOVE.W    #-1,TRACK    ;We don't know where we are
  890.     BRA.S    SUBRP10
  891.  
  892. SUBRP90    MOVEM.L    (SP)+,A2    ;Restore A2
  893.     RTS
  894.  
  895. ;======================================================================
  896. ;Routine to turn the selected drive motor on or off. It returns the
  897. ; initial state of the motor (on or off) in D0.
  898. ; On = 1; Off = 0.
  899. ;
  900. DOMOTOR    MOVE.L    D2,-(SP)
  901.  
  902.     TST.L    D0
  903.     SEQ    D1
  904.     ANDI.B    #$0080,D1
  905.  
  906.     MOVE.B    CIABBX,D2
  907.     ANDI.B    #$0080,D2
  908.     CMP.B    D1,D2
  909.     BEQ    LB0C2
  910.     BCLR    #7,CIABBX    ;Turn on motor
  911.     OR.B    D1,CIABBX
  912.  
  913.     MOVEQ    #-1,D1
  914.     EOR.B    D2,D1
  915.     MOVE.B    D1,CIABB.L
  916.     MOVE.B    CIABBX,CIABB.L
  917.  
  918.     BTST    #7,CIABBX    ;Is motor turned on?
  919.     BNE    LB0C2        ;Branch if not
  920.     MOVE.L    #500000,D0    ;Wait half a second for motor to
  921.     BSR    DELAY        ; come up to speed
  922. LB0C2
  923.     MOVEQ    #0,D0
  924.     BTST    #7,D2
  925.     SEQ    D0
  926.  
  927.     MOVE.L    (SP)+,D2
  928.     RTS
  929.  
  930. ;----------------------------------------------------------------------
  931. ;Routine to seek the track number in D0.
  932. ; D0 returns with error code (= 0 if no errors)
  933. ;
  934. DOSEEK    MOVEM.L    D2-D3,-(SP)    ;Save registers
  935.  
  936.     MOVE.W    TRACK,D2    ;Get current track number
  937.     BPL    LB002        ;Branch if it is known
  938.     MOVE.L    D0,D2        ;Otherwise we don't know where we are
  939.     BSR    STEPTO0        ;Move head to track 0
  940.     TST.L    D0        ;Any errors detected?
  941.     BNE    LB06C        ;Branch if so -- exit with error code
  942.     EXG    D0,D2        ;Get track number back in D0, (D2=0)
  943. LB002
  944.     CMP.W    D0,D2        ;Is the head already on our track?
  945.     BEQ    LB06A        ;Branch if so -- exit with no errors
  946.     MOVE.L    D0,D3        ;Save desired track number in D3
  947.  
  948.     MOVE.B    CIABBX,D1    ;Get copy of the control port
  949.     BSET    #2,D1        ;Assume we want the lower head
  950.     BTST    #0,D3        ;Is this an odd or even track number?
  951.     BEQ.S    LB020        ;Branch if even -- use lower side
  952.     BCLR    #2,D1        ;Else, select upper head
  953. LB020
  954.     MOVE.B    D1,CIABBX    ;Update port control bits (and the copy)
  955.     MOVE.B    D1,CIABB.L
  956.  
  957.     MOVE.W    D3,TRACK    ;Update current track number
  958.     LSR.W    #1,D2        ;D2 = current track, D3 = desired track
  959.     LSR.W    #1,D3        ;Divide by 2 to get cylinder number
  960.     SUB.W    D3,D2        ;D2 = number of cylinders to move head
  961.     BLO.S    LB03E        ; away from center (think backwards)
  962.     BHI.S    LB04A
  963.     BRA.S    LB06A        ;We don't need to move the head - exit
  964.  
  965. LB03E    BCLR    #1,D1        ;Seek toward center
  966.     MOVE.B    D1,CIABBX
  967.     NEG.W    D2        ;Make number of steps positive
  968.     BRA.S    LB058        ;Enter step loop
  969.  
  970. LB04A    BSET    #1,D1        ;Seek toward track 0
  971.     MOVE.B    D1,CIABBX
  972.     BRA.S    LB058        ;Enter step loop
  973.  
  974. LB054    BSR    DOSTEP        ;Step head in selected direction
  975. LB058    DBF     D2,LB054    ;loop for D2 steps
  976.  
  977.     MOVE.L    #15000,D0    ;Wait 15 milliseconds for head to settle
  978.     BSR    DELAY
  979.  
  980. LB06A    MOVEQ    #0,D0        ;Indicate no errors
  981.  
  982. LB06C    MOVEM.L    (SP)+,D2-D3    ;Restore registers
  983.     RTS
  984.  
  985. ;----------------------------------------------------------------------
  986. ;Routine to step head to track 0.
  987. ; D0 returns with error code (0 = no errors)
  988. ;
  989. STEPTO0    MOVEM.L    D2,-(SP)
  990.  
  991.     MOVE.B    CIABBX,D0
  992.     BSET    #2,D0        ;Select lower head
  993.     BCLR    #1,D0        ;Seek toward the center
  994.     MOVE.B    D0,CIABB.L
  995.     MOVE.B    D0,CIABBX
  996.  
  997.     MOVEQ    #40,D2        ;Set maximum tries
  998. LAF90    BTST    #4,CIAA.L    ;On track 0?
  999.     BNE.S    LAFA2        ;Branch if not
  1000.     BSR    DOSTEP
  1001.     DBF     D2,LAF90
  1002.  
  1003. LAFA2    BSET    #1,CIABBX    ;Seek toward track 0
  1004.     CLR.W    TRACK        ;Record that we will be on track 0
  1005.     MOVE.W    #100,D2        ;Set maximum steps to 100
  1006.     BRA.S    LAFB6        ;Enter step loop
  1007.  
  1008. LAFB2    BSR    DOSTEP        ;Step head toward track 0
  1009. LAFB6    BTST    #4,CIAA.L    ;On track 0?
  1010.     DBEQ    D2,LAFB2    ;Exit loop if so
  1011.  
  1012.     MOVE.B    CIAA.L,D2
  1013.     BTST    #4,D2        ;On track 0?
  1014.     BEQ.S    LAFD6        ;Branch if so
  1015.     MOVEQ    #30,D0        ;Seek error while verifying posn
  1016.     BRA.S    LAFE2        ;Exit
  1017.  
  1018. LAFD6    MOVE.L    #15000,D0    ;Wait 15 milliseconds for head to settle
  1019.     BSR    DELAY
  1020.  
  1021.     MOVEQ    #0,D0        ;Indicate no errors
  1022. LAFE2    MOVEM.L    (SP)+,D2
  1023.     RTS
  1024.  
  1025. ;----------------------------------------------------------------------
  1026. ;Routine to step the head
  1027. ;
  1028. DOSTEP    MOVE.B    CIABBX,D0
  1029.     LEA    CIABB.L,A1    ;Point to output control port
  1030.     MOVE.B    D0,D1        ;Save copy of original port bits
  1031.     BCLR    #0,D0        ;Command to step the head
  1032.     MOVE.B    D0,(A1)        ;Send command
  1033.     NOP            ;Delay for step pulse width
  1034.     NOP
  1035.     MOVE.B    D1,(A1)        ;terminate pulse
  1036.  
  1037.     MOVE.L    #3000,D0    ;Wait at least 3 milliseconds for
  1038.     BSR    DELAY        ; step to occur
  1039.  
  1040.     MOVE.B    CIABBX,CIABB.L
  1041.     RTS
  1042.  
  1043. ;======================================================================
  1044. ;Routine to write a track.
  1045. ; Inputs D0 = number of encoded bytes to write
  1046. ;     A0 = pointer to buffer
  1047. ; Outputs D0 = error code (0 = no errors)
  1048. ;
  1049. WRITTRK    MOVEM.L    D2/A2,-(SP)
  1050.  
  1051.     MOVEA.L    A0,A2
  1052.     MOVE.L    D0,D2
  1053.  
  1054.     MOVE.B    CIABBX,CIABB.L
  1055.     MOVE.W    #$4000,DSKLEN.L    ;Make sure DMA is off
  1056.     MOVE.L    #1000,D0    ;Wait a millisecond
  1057.     BSR    DELAY
  1058.  
  1059.     LEA    IOBASE.L,A1
  1060.     MOVE.L    A2,DSKPTH-IOBASE(A1)    ;Set DMA pointer to buffer
  1061.     MOVE.W    #$1002,INTREQ-IOBASE(A1) ;Clear disk sync & blk done
  1062.  
  1063. ;    BTST    #2,CIAA.L    ;Has the disk been changed?
  1064. ;    BNE.S    LB24A        ;Branch if not
  1065.     BRA.S    LB24A        ;Ignore disk changed error
  1066.  
  1067. LB244    MOVEQ    #29,D2        ;io_Error: Disk changed
  1068.     BRA    LB2AE
  1069.  
  1070. LB24A    BTST    #3,CIAA.L    ;Is disk write protected?
  1071.     BEQ    LB2BA        ;Branch if it is
  1072.  
  1073. ;Set precomp at 140 ns when TRACK is beyond half way:
  1074.     MOVE.W    #$6000,ADKCON-IOBASE(A1)    ;No precomp
  1075.     MOVE.W    TRACK,D1
  1076.     CMPI.W    #81,D1        ;Half way?
  1077.     BLT.S    LB26C        ;Branch if lower half
  1078.     MOVE.W    #$A000,D1    ;Precomp 140ns
  1079.     BRA.S    LB270
  1080. LB26C    MOVE.W    #$8000,D1    
  1081. LB270    MOVE.W    D1,ADKCON-IOBASE(A1)    ;Set precomp
  1082.  
  1083.     LSR.W    #1,D2        ;Divide by 2 to get number of words
  1084.     ORI.W    #$C000,D2    ;Enable write and DMA
  1085.     MOVE.W    D2,DSKLEN-IOBASE(A1)    ;Start DMA
  1086.     MOVE.W    D2,DSKLEN-IOBASE(A1)
  1087.  
  1088. WRT30    MOVE.W    INTREQR-IOBASE(A1),D0    ;Wait for disk block finished
  1089.     BTST    #1,D0
  1090.     BEQ.S    WRT30
  1091.  
  1092.     MOVE.L    #2000,D0    ;Wait 2 milliseconds
  1093.     BSR    DELAY
  1094.  
  1095.     MOVE.W    #$4000,36(A1)    ;Leave DMA in a safe state
  1096.  
  1097. ;    BTST    #2,CIAA.L    ;Has the disk been changed?
  1098. ;    BEQ.S    LB244        ;Branch if so
  1099.     MOVEQ    #0,D2        ;Indicate no errors
  1100.  
  1101. LB2AE    MOVE.L    D2,D0        ;Return error code in D0
  1102.  
  1103.     MOVEM.L    (SP)+,D2/A2
  1104.     RTS
  1105.  
  1106.  
  1107. LB2BA    MOVEQ    #28,D2        ;io_Error: Write protected
  1108.     BRA.S    LB2AE        ;Exit
  1109.  
  1110. ;----------------------------------------------------------------------
  1111. ;Routine to read a track.
  1112. ; Inputs D0 = number of encoded bytes to read
  1113. ;     A0 = pointer to encoded buffer
  1114. ; Outputs D0 = error code (0 = no errors)
  1115. ;
  1116. READTRK    MOVEM.L    D2/A2,-(SP)    ;Save registers
  1117.  
  1118.     MOVEA.L    A0,A2
  1119.     MOVE.L    D0,D2
  1120.  
  1121.     MOVE.B    CIABBX,CIABB.L
  1122.     MOVE.W    #$4000,DSKLEN.L    ;Turn off DMA
  1123.     MOVE.L    #1000,D0    ;Wait  a millisecond
  1124.     BSR    DELAY
  1125.  
  1126.     LEA    IOBASE.L,A1
  1127.     MOVE.L    A2,DSKPTH-IOBASE(A1)    ;Set pointer to buffer for DMA
  1128.     MOVE.W    #$1002,INTREQ-IOBASE(A1) ;Clear disk sync reg & blk done
  1129.  
  1130. ;    BTST    #2,CIAA.L    ;Has the disk been changed?
  1131. ;    BNE.S    LB1C2        ;Branch if not
  1132.     BRA.S    LB1C2        ;Ignore disk changed
  1133.  
  1134. LB1BE    MOVEQ    #29,D2        ;Error: Disk changed or not present
  1135.     BRA.S    LB1F2        ;Exit with error code
  1136. LB1C2
  1137.     LSR.W    #1,D2        ;Divide by 2 to get words
  1138.     ORI.W    #$8000,D2    ;Set DMA enable bit
  1139.     MOVE.W    D2,DSKLEN-IOBASE(A1) ;Command it twice to start DMA
  1140.     MOVE.W    D2,DSKLEN-IOBASE(A1)
  1141.  
  1142. RDT30    MOVE.W    INTREQR-IOBASE(A1),D0    ;Wait for disk block finished
  1143.     BTST    #1,D0
  1144.     BEQ.S    RDT30
  1145.  
  1146.     LEA    IOBASE.L,A1
  1147.     MOVE.W    #$4000,DSKLEN-IOBASE(A1) ;Prevent accidental writes
  1148.  
  1149. ;    BTST    #2,CIAA.L    ;Has the disk been changed?
  1150. ;    BEQ.S    LB1BE        ;Branch if it has -- exit (circuitously)
  1151.  
  1152.     MOVEQ    #0,D2        ;Indicate no errors
  1153. LB1F2    MOVE.L    D2,D0
  1154.  
  1155.     MOVEM.L    (SP)+,D2/A2    ;Restore registers
  1156.     RTS
  1157.  
  1158. ;----------------------------------------------------------------------
  1159. ;This routine aligns raw read data and verifies the header and checksum.
  1160. ; It returns an error code in D0 (io_Error).
  1161. ;
  1162. SUBRXQ    MOVEM.L    D2-D6/A2,-(SP)    ;Save registers
  1163.     LINK    A4,#-16        ;Allocate space for local variables
  1164.  
  1165.     MOVEA.L    PTR2,A2
  1166.     LEA    1664(A2),A2    ;Skip gap
  1167.     MOVEA.L    A2,A0
  1168.     ADDQ.L    #2,A0        ;Skip rest of gap
  1169.     MOVE.L    #1660 +2*544,D0    ;Maximum scan is a gap + a sector
  1170.     BSR    SUBRXO        ;Scan for sync bytes
  1171.     CMPA.L    #-1,A0
  1172.     BEQ    ERRX21        ;Couldn't find sync bytes
  1173.  
  1174.     MOVE.L    A0,D5        ;Save pointer to sync table
  1175.     MOVE.L    D0,D2        ;D2 = number of bits to shift
  1176.  
  1177.     ADDQ.L    #8,A0
  1178.     MOVEQ    #9,D4        ;Loop 10 times
  1179.     MOVEQ    #0,D6        ;Initialize checksum to zero
  1180.     TST.L    D2
  1181.     BNE.S    LBC34        ;Branch if bits are shifted
  1182.                 ;Otherwise bits are aligned
  1183.     MOVE.L    (A0),-8(A4)    ;Save long word after sync
  1184.     MOVE.L    4(A0),-4(A4)    ;Save next long word
  1185.  
  1186.     MOVE.L    #$55555555,D1    ;Compute checksum of header
  1187. LBC20    MOVE.L    (A0)+,D0
  1188.     AND.L    D1,D0        ;Remove clock bits
  1189.     EOR.L    D0,D6        ;Update "checksum" (really only parity)
  1190.     DBF     D4,LBC20    ;Loop 10 times (= 20 encoded bytes)
  1191.  
  1192.     MOVE.L    (A0)+,-16(A4)    ;Get encoded header checksum from
  1193.     MOVE.L    (A0),-12(A4)    ; buffer (high, low words)
  1194.     BRA.S    LBC68
  1195. LBC34
  1196.     BSR    SUBRXR        ;Decode word
  1197.     MOVE.L    D0,-8(A4)
  1198.     BSR    SUBRXR
  1199.     MOVE.L    D0,-4(A4)
  1200.     MOVEA.L    D5,A0
  1201.     ADDQ.L    #8,A0
  1202.  
  1203. LBC48    BSR    SUBRXR        ;Decode word
  1204.     ANDI.L    #$55555555,D0
  1205.     EOR.L    D0,D6
  1206.     DBF     D4,LBC48
  1207.  
  1208.     BSR    SUBRXR
  1209.     MOVE.L    D0,-16(A4)
  1210.     BSR    SUBRXR
  1211.     MOVE.L    D0,-12(A4)
  1212. LBC68
  1213.     LEA    -16(A4),A0    ;Point to header checksum
  1214.     BSR    DECOD_L        ;Decode 8 bytes to get one long word
  1215.     CMP.L    D0,D6        ;Compare to value computed above
  1216.     BNE    ERRX27        ;Branch if header checksum error
  1217.  
  1218.     LEA    -8(A4),A0    ;Point to format byte, track, sector
  1219.     BSR    DECOD_L        ;Decode to get 4 bytes of info
  1220.     MOVE.L    D0,D3        ;Save decoded bytes in D3
  1221.     MOVE.L    D3,-(SP)    ; and on the stack
  1222.     CMPI.B    #$FF,0(SP)    ;Check for format byte ($FF)
  1223.     BNE    ERRX27        ;Unable to read sector header
  1224.  
  1225.     MOVE.B    1(SP),D0    ;Check track number
  1226.     CMP.B    TRACKD+1,D0
  1227.     BNE    ERRX27        ;Branch if wrong track
  1228.  
  1229.     MOVE.L    (SP)+,D3
  1230.     MOVEQ    #0,D0
  1231.     MOVE.B    D3,D0        ;Number of sectors until end of write
  1232.     MULU    #544*2,D0    ;Compute offset into encoded data
  1233.     MOVEA.L    D5,A0        ;Point to entry in sync table
  1234.     MOVEA.L    A2,A1        ;Pointer to maximum scan position
  1235.     MOVE.L    D2,D1        ;Index into sync table
  1236.     MOVE.L    D0,D4        ;Offset into encoded data (end of write)
  1237.     BSR    SUBRXS        ;Let the blitter align the sectors
  1238.  
  1239.     MOVEQ    #0,D2
  1240.     MOVE.B    D3,D2
  1241.     SUBI.L    #11,D2
  1242.     NEG.L    D2
  1243.     BEQ.S    LBCE6
  1244.     ADD.L    D4,D5
  1245.  
  1246.     MOVE.L    #1660,D0
  1247.     MOVEA.L    D5,A0
  1248.     ADDQ.L    #2,A0
  1249.     BSR    SUBRXO
  1250.     CMPA.L    #-1,A0
  1251.     BEQ    ERRX26        ;Incorrect number of sectors on track
  1252.  
  1253.     MOVE.L    D0,D1        ;Get number of bits of shift (should
  1254.     MOVEA.L    A2,A1        ; be zero)
  1255.     ADDA.L    D4,A1
  1256.     MOVE.L    D2,D0
  1257.     MULU    #544*2,D0
  1258.     BSR    SUBRXS
  1259. LBCE6    MOVEA.L    A2,A0
  1260.     ADDA.L    D4,A0
  1261.     BSR    SUBRXK
  1262.     LEA    544*2*11(A2),A0
  1263.     MOVE.W    #$AAA8,D0
  1264.     BTST    #0,-1(A0)
  1265.     BEQ    LBD04
  1266.     BCLR    #15,D0
  1267. LBD04
  1268.     MOVE.W    D0,(A0)
  1269.     MOVE.W    #$AAAA,(A2)
  1270.     MOVEQ    #0,D4
  1271.     MOVEQ    #11,D2
  1272.     MOVE.W    D3,D5
  1273.     LSR.W    #8,D5
  1274.  
  1275. LBD12    CMPI.L    #$2AAAAAAA,0(A2,D4.W)    ;2 bytes of MFM encoded 00 data
  1276.     BEQ.S    LBD28
  1277.     CMPI.L    #$AAAAAAAA,0(A2,D4.W)
  1278.     BNE    ERRX22        ;Error in sector preamble
  1279. LBD28
  1280.     CMPI.L    #$44894489,4(A2,D4.W)    ;sync bytes ($A1 $A1)
  1281.     BNE    ERRX22
  1282.  
  1283.     LEA    8(A2,D4.W),A0    ;Location of encoded bytes
  1284.     MOVEQ    #40,D1        ;Number of encoded bytes
  1285.     BSR    DOCKSUM        ;Compute checksum of header
  1286.     MOVE.L    D0,D6        ;Save checksum in D6
  1287.  
  1288.     LEA    48(A2,D4.W),A0
  1289.     BSR    DECOD_L        ;Decode header checksum
  1290.     CMP.L    D6,D0        ;Compare checksums
  1291.     BNE    ERRX24        ;Branch if header field has bad checksum
  1292.  
  1293.     LEA    8(A2,D4.W),A0    ;Decode format byte, track and sector
  1294.     BSR    DECOD_L        ; numbers, etc.
  1295.     MOVE.L    D0,-(SP)
  1296.     CMPI.B    #$FF,0(SP)    ;Format byte must be $FF
  1297.     BNE    ERRX23        ;Error in sector identifier
  1298.  
  1299.     MOVE.B    1(SP),D1    ;Get track number
  1300.     CMP.B    TRACKD+1,D1
  1301.     BNE    ERRX23        ;Error in sector identifier
  1302.  
  1303.     MOVE.B    2(SP),D1    ;Get sector number
  1304.     CMP.B    D5,D1
  1305.     BNE    ERRX23        ;Error in sector identifier
  1306.  
  1307.     MOVE.B    D2,3(SP)    ;Set number of sectors until end
  1308.     MOVE.L    (SP)+,D0
  1309.     LEA    8(A2,D4.W),A0    ;Location to store encoded data
  1310.     BSR    ENCOD_L        ;Encode and store data
  1311.  
  1312.     LEA    8(A2,D4.W),A0    ;Location of encoded header data
  1313.     MOVEQ    #40,D1        ;Number of encoded bytes
  1314.     BSR    DOCKSUM        ;Compute checksum (D0)
  1315.  
  1316.     LEA    48(A2,D4.W),A0    ;Encode and store header checksum
  1317.     BSR    ENCOD_L        ; at A0
  1318.  
  1319.     LEA    64(A2,D4.W),A0    ;Location of encoded data
  1320.     MOVE.W    #1024,D1    ;Number of encoded bytes
  1321.     BSR    DOCKSUM        ;Compute checksum (D0)
  1322.     MOVE.L    D0,D6        ;Save it in D6
  1323.  
  1324.     LEA    56(A2,D4.W),A0    ;Decode data checksum that was read in
  1325.     BSR    DECOD_L
  1326.     CMP.L    D6,D0        ;Does it agree with computed checksum?
  1327.     BNE    ERRX25        ;Branch if not -- bad checksum
  1328.  
  1329.     SUBQ.L    #1,D2
  1330.     ADDQ.B    #1,D5
  1331.     CMPI.B    #11,D5
  1332.     BLT.S    LBDC0
  1333.     MOVEQ    #0,D5
  1334. LBDC0
  1335.     ADDI.W    #544*2,D4
  1336.     CMPI.W    #544*2*11,D4
  1337.     BNE    LBD12
  1338.     MOVE.L    D3,D1
  1339.     LSR.L    #8,D1
  1340.     MOVEQ    #0,D0
  1341.     MOVE.B    D1,D0
  1342.  
  1343. ERRX90    UNLK    A4
  1344.     MOVEM.L    (SP)+,D2-D6/A2
  1345.     RTS
  1346.  
  1347.  
  1348. ERRX21    MOVEQ    #21,D0        ;Couldn't find sector header
  1349.     BRA.S    ERRX90
  1350.  
  1351. ERRX27    MOVEQ    #27,D0        ;Unable to read sector header
  1352.     BRA.S    ERRX90
  1353.  
  1354. ERRX22    MOVEQ    #22,D0        ;Error in sector preamble
  1355.     BRA.S    ERRX90
  1356.  
  1357. ERRX23    MOVEQ    #23,D0        ;Error in sector identifier
  1358.     BRA.S    ERRX90
  1359.  
  1360. ERRX24    MOVEQ    #24,D0        ;Header field has bad checksum
  1361.     BRA.S    ERRX90
  1362.  
  1363. ERRX25    MOVEQ    #25,D0        ;Sector data field has bad checksum
  1364.     BRA.S    ERRX90
  1365.  
  1366. ERRX26    MOVEQ    #26,D0        ;Incorrect number of sectors on track
  1367.     BRA.S    ERRX90
  1368.  
  1369. ;======================================================================
  1370. ;MFM Encode and store the data in D0. The input data (D0) is four bytes,
  1371. ; and the stored data is eight bytes.
  1372. ; Inputs:
  1373. ;    D0 = Four bytes of data to be encoded and stored
  1374. ;    A0 = Location to store encoded data (bumped by 8 bytes).
  1375. ;
  1376. ENCOD_L    MOVEM.L    D2-D3,-(SP)
  1377.     MOVE.L    D0,D3
  1378.  
  1379.     LSR.L    #1,D0        ;Encode the odd bits
  1380.     BSR    SUBRXH
  1381.  
  1382.     MOVE.L    D3,D0        ;Encode the even bits
  1383.     BSR    SUBRXH
  1384.  
  1385.     BSR    SUBRXK
  1386.  
  1387.     MOVEM.L    (SP)+,D2-D3
  1388.     RTS
  1389.  
  1390. ;----------------------------------------------------------------------
  1391. ;MFM Encode the even bits of a long word. The odd bits are used as clock
  1392. ; bits. A clock bit is set only when the two adjacent data bits are both
  1393. ; zero.
  1394. ; Inputs:
  1395. ;    D0 = Data to be MFM encoded (even bits only)
  1396. ;    A0 = Location to store encoded data
  1397. ;
  1398. SUBRXH    ANDI.L    #$55555555,D0    ;Get the even data bits
  1399.     MOVE.L    D0,D2
  1400.  
  1401.     EORI.L    #$55555555,D2    ;Turn the zeros into ones
  1402.     MOVE.L    D2,D1        ;Copy inverted data into D1
  1403.  
  1404.     LSL.L    #1,D2        ;<-- D2
  1405.     LSR.L    #1,D1        ;    D1 -->
  1406.     BSET    #31,D1        ;Assume last bit of last data was a one
  1407.     AND.L    D2,D1        ;Set clock bit if there were two zeros
  1408.     OR.L    D1,D0        ; in a row. Combine clocks with data
  1409.     BTST    #0,-1(A0)    ;Check last data bit of preceding data
  1410.     BEQ.S    LB982        ;Branch if it was a zero -- leave clock
  1411.     BCLR    #31,D0        ; bit alone, otherwise it's not needed
  1412. LB982
  1413.     MOVE.L    D0,(A0)+    ;Store encoded data in buffer
  1414.     RTS
  1415.  
  1416. ;----------------------------------------------------------------------
  1417. ;Routine to encode and move a block of data (write a sector).
  1418. ;Inputs:
  1419. ;    D0 = Number of bytes to encode
  1420. ;    A0 = Pointer to bytes to be encoded
  1421. ;    A1 = Pointer to location to hold encoded bytes
  1422. ;
  1423. ENCODE    LINK    A2,#-30        ;Reserve space for blit structure
  1424.  
  1425.     MOVE.W    D0,D1
  1426.     LSL.W    #2,D1        ;Number of bytes *2
  1427.     ORI.W    #$0008,D1    ; add 8 (BLITSIZE)
  1428.     MOVE.W    D1,-10(A2)
  1429.     MOVEM.L    D0/A0-A1,-22(A2)
  1430.     MOVE.L    A3,-4(A2)
  1431.  
  1432.  
  1433.     LEA    IOBASE.L,A1
  1434. ENC20    MOVE.W    DMACONR-IOBASE(A1),D0    ;Wait for blitter not busy
  1435.     BTST    #14,D0
  1436.     BNE.S    ENC20
  1437.  
  1438.     MOVE.W    #$0040,INTREQ-IOBASE(A1) ;Clear blitter finished bit
  1439.  
  1440.     MOVEA.L    #$DFF000,A0
  1441.     LEA    -30(A2),A1    ;Point to blit structure
  1442.     BSR    SUBRXZ
  1443.  
  1444.     LEA    IOBASE.L,A1
  1445. ENC30    MOVE.W    INTREQR-IOBASE(A1),D0    ;Wait for blitter finished
  1446.     BTST    #6,D0
  1447.     BEQ.S    ENC30
  1448.  
  1449.  
  1450.     LEA    IOBASE.L,A1
  1451. ENC40    MOVE.W    DMACONR-IOBASE(A1),D0    ;Wait for blitter not busy
  1452.     BTST    #14,D0
  1453.     BNE.S    ENC40
  1454.  
  1455.     MOVE.W    #$0040,INTREQ-IOBASE(A1) ;Clear blitter finished bit
  1456.  
  1457.     MOVEA.L    #$DFF000,A0
  1458.     LEA    -30(A2),A1    ;Point to blit structure
  1459.     BSR    SUBRY
  1460.  
  1461.     LEA    IOBASE.L,A1
  1462. ENC50    MOVE.W    INTREQR-IOBASE(A1),D0    ;Wait for blitter finished
  1463.     BTST    #6,D0
  1464.     BEQ.S    ENC50
  1465.  
  1466.  
  1467.     LEA    IOBASE.L,A1
  1468. ENC60    MOVE.W    DMACONR-IOBASE(A1),D0    ;Wait for blitter not busy
  1469.     BTST    #14,D0
  1470.     BNE.S    ENC60
  1471.  
  1472.     MOVE.W    #$0040,INTREQ-IOBASE(A1) ;Clear blitter finished bit
  1473.  
  1474.     MOVEA.L    #$DFF000,A0
  1475.     LEA    -30(A2),A1    ;Point to blit structure
  1476.     BSR    SUBRZ
  1477.  
  1478.     LEA    IOBASE.L,A1
  1479. ENC70    MOVE.W    INTREQR-IOBASE(A1),D0    ;Wait for blitter finished
  1480.     BTST    #6,D0
  1481.     BEQ.S    ENC70
  1482.  
  1483.  
  1484.     LEA    IOBASE.L,A1
  1485. ENC80    MOVE.W    DMACONR-IOBASE(A1),D0    ;Wait for blitter not busy
  1486.     BTST    #14,D0
  1487.     BNE.S    ENC80
  1488.  
  1489.     MOVE.W    #$0040,INTREQ-IOBASE(A1) ;Clear blitter finished bit
  1490.  
  1491.     MOVEA.L    #$DFF000,A0
  1492.     LEA    -30(A2),A1    ;Point to blit structure
  1493.     BSR    SUBRAA
  1494.  
  1495.     LEA    IOBASE.L,A1
  1496. ENC90    MOVE.W    INTREQR-IOBASE(A1),D0    ;Wait for blitter finished
  1497.     BTST    #6,D0
  1498.     BEQ.S    ENC90
  1499.  
  1500.     MOVEM.L    -22(A2),D0/A0-A1
  1501.     MOVE.L    D0,D1
  1502.  
  1503.     MOVEA.L    A1,A0
  1504.     BSR    SUBRXK
  1505.  
  1506.     ADDA.L    D1,A0
  1507.     BSR    SUBRXK
  1508.  
  1509.     ADDA.L    D1,A0
  1510.     BSR    SUBRXK
  1511.  
  1512.     UNLK    A2        ;Release local variables
  1513.     RTS
  1514.  
  1515. ;----------------------------------------------------------------------
  1516. ;Routine to handle the blitter.
  1517. ; Inputs:
  1518. ;    A0 = $DFF000
  1519. ;    A1 = Pointer to blit structure (node)
  1520. ;
  1521. SUBRXZ    MOVE.L    A5,-(SP)
  1522.  
  1523.     MOVEA.L    A1,A5
  1524.     BSR    SETBLIT
  1525.     MOVEA.L    A5,A1
  1526.  
  1527.     MOVEM.L    8(A1),D0-D1/A5
  1528.     MOVE.L    D1,76(A0)
  1529.     MOVE.L    D1,80(A0)
  1530.     MOVE.L    A5,84(A0)    ;Disk resource
  1531.     MOVE.W    #$1DB1,BLTCON0-IOBASE(A0)
  1532.     MOVE.W    #$0000,BLTCON1-IOBASE(A0)
  1533.     MOVE.W    20(A1),BLTSIZE-IOBASE(A0)
  1534.  
  1535.     MOVEA.L    (SP)+,A5
  1536.     RTS
  1537.  
  1538. ;----------------------------------------------------------------------
  1539. ;Routine to handle the blitter.
  1540. ; Inputs:
  1541. ;    A0 = $DFF000
  1542. ;    A1 = Pointer to blit structure (node)
  1543. ;
  1544. ;
  1545. SUBRY    MOVE.L    A5,-(SP)
  1546.  
  1547.     MOVEM.L    8(A1),D0-D1/A5
  1548.     MOVE.L    A5,76(A0)
  1549.     MOVE.L    D1,80(A0)
  1550.     MOVE.L    A5,84(A0)
  1551.  
  1552.     MOVE.W    #$2D8C,BLTCON0-IOBASE(A0)
  1553.     MOVE.W    20(A1),BLTSIZE-IOBASE(A0)
  1554.  
  1555.     MOVEA.L    (SP)+,A5
  1556.     RTS
  1557.  
  1558. ;----------------------------------------------------------------------
  1559. ;Routine to handle the blitter.
  1560. ; Inputs:
  1561. ;    A0 = $DFF000
  1562. ;    A1 = Pointer to blit structure (node)
  1563. ;
  1564. ;
  1565. SUBRZ    MOVE.L    A5,-(SP)
  1566.  
  1567.     MOVEM.L    8(A1),D0-D1/A5
  1568.     ADD.L    D0,D1
  1569.     SUBQ.L    #2,D1
  1570.     ADDA.L    D0,A5
  1571.     ADDA.L    D0,A5
  1572.     SUBQ.L    #2,A5
  1573.     MOVE.L    D1,76(A0)
  1574.     MOVE.L    D1,80(A0)
  1575.     MOVE.L    A5,84(A0)
  1576.  
  1577.     MOVE.W    #$0DB1,BLTCON0-IOBASE(A0)
  1578.     MOVE.W    #$1002,BLTCON1-IOBASE(A0)
  1579.     MOVE.W    20(A1),BLTSIZE-IOBASE(A0)
  1580.  
  1581.     MOVEA.L    (SP)+,A5
  1582.     RTS
  1583.  
  1584. ;----------------------------------------------------------------------
  1585. ;Routine to handle the blitter.
  1586. ; Inputs:
  1587. ;    A0 = $DFF000
  1588. ;    A1 = Pointer to blit structure (node)
  1589. ;
  1590. SUBRAA    MOVE.L    A5,-(SP)    ;Save A5
  1591.  
  1592.     MOVEM.L    8(A1),D0-D1/A5
  1593.     ADDA.L    D0,A5
  1594.     MOVE.L    A5,76(A0)
  1595.     MOVE.L    D1,80(A0)
  1596.     MOVE.L    A5,84(A0)
  1597.  
  1598.     MOVE.W    #$1D8C,BLTCON0-IOBASE(A0)
  1599.     MOVE.W    #$0000,BLTCON1-IOBASE(A0)
  1600.     MOVE.W    20(A1),BLTSIZE-IOBASE(A0) ;Set size and go
  1601.  
  1602.     MOVEA.L    (SP)+,A5    ;Restore A5
  1603.     RTS
  1604.  
  1605. ;----------------------------------------------------------------------
  1606. ;
  1607. SUBRXK    MOVE.B    (A0),D0
  1608.     BTST    #0,-1(A0)
  1609.     BNE.S    LB9CC
  1610.     BTST    #6,D0
  1611.     BNE.S    LB9D2
  1612.     BSET    #7,D0
  1613.     BRA.S    LB9D0
  1614.  
  1615. LB9CC    BCLR    #7,D0
  1616. LB9D0    MOVE.B    D0,(A0)
  1617. LB9D2    RTS
  1618.  
  1619. ;======================================================================
  1620. ;Decode an MFM-encoded, 8-byte block of data pointed to by A0.
  1621. ; Return the long word result in D0.
  1622. ;
  1623. DECOD_L    MOVE.L    (A0)+,D0    ;Get odd bits
  1624.     MOVE.L    (A0)+,D1    ;Get even bits
  1625.     ANDI.L    #$55555555,D0    ;Mask off the clock bits
  1626.     ANDI.L    #$55555555,D1
  1627.     LSL.L    #1,D0        ;Shift odd bits into position
  1628.     OR.L    D1,D0        ;Combine with even bits
  1629.     RTS            ;Return with result in D0
  1630.  
  1631. ;----------------------------------------------------------------------
  1632. ;Routine to decode and move a block of data (i.e. read sector).
  1633. ; Inputs: D0 = Number of bytes to decode (512, number after decoding)
  1634. ;      A0 = Pointer to decoded buffer (io_Data)
  1635. ;      A1 = Pointer to encoded track buffer data
  1636. ;
  1637. ;This routine uses the blitter. The following is the blit structure
  1638. ; formerly used by the graphics library routine QBlit:
  1639. ;
  1640. ;    A1 -->    -30            Pointer to next blit node
  1641. ;        -26    SUBREE        (not used)
  1642. ;        -22    D0        call clean up routine?
  1643. ;        -21            (dummy)
  1644. ;        -20            blit size
  1645. ;        -18    A0        beamsync
  1646. ;        -16            clean up
  1647. ;        -14    A1    
  1648. ;        -10    D0 *4 ! 8
  1649. ;        -6
  1650. ;        -4    A3
  1651. ;    A2 -->     0
  1652. ;
  1653. ;
  1654. DECODE    LINK    A2,#-30        ;Reserve space for local variables
  1655.     MOVEM.L    D0/A0-A1,-22(A2) ;Save registers in this blit structure
  1656.  
  1657.     LSL.W    #2,D0        ;*4
  1658.     ORI.W    #$0008,D0
  1659.     MOVE.W    D0,-10(A2)
  1660.     MOVE.L    A3,-4(A2)
  1661.  
  1662.     LEA    IOBASE.L,A1
  1663. DEC20    MOVE.W    DMACONR-IOBASE(A1),D0    ;Wait for blitter not busy
  1664.     BTST    #14,D0
  1665.     BNE.S    DEC20
  1666.  
  1667.     MOVE.W    #$0040,INTREQ-IOBASE(A1) ;Clear blitter finished bit
  1668.  
  1669.     MOVEA.L    #$DFF000,A0
  1670.     LEA    -30(A2),A1    ;Set pointer to blit structure
  1671.     BSR    SUBREE
  1672.  
  1673.     LEA    IOBASE.L,A1
  1674. DEC30    MOVE.W    INTREQR-IOBASE(A1),D0    ;Wait for blitter finished
  1675.     BTST    #6,D0
  1676.     BEQ.S    DEC30
  1677.  
  1678.     MOVEM.L    -22(A2),D0/A0-A1    ;Restore registers and stack
  1679.     UNLK    A2        ;Release local variable space
  1680.     RTS
  1681.  
  1682. ;----------------------------------------------------------------------
  1683. ;Routine to handle the blitter.
  1684. ; Inputs:
  1685. ;    A0 = $DFF000
  1686. ;    A1 = Pointer to blit structure (node)
  1687. ;
  1688. SUBREE    MOVE.L    A5,-(SP)
  1689.  
  1690.     MOVEA.L    A1,A5
  1691.     BSR    SETBLIT
  1692.  
  1693.     MOVEA.L    A5,A1
  1694.     MOVEM.L    8(A1),D0-D1/A5
  1695.     ADDA.L    D0,A5
  1696.     SUBQ.L    #1,A5
  1697.     MOVE.L    A5,BLTAPTH-IOBASE(A0)
  1698.     ADDA.L    D0,A5
  1699.     MOVE.L    A5,BLTBPTH-IOBASE(A0)
  1700.     ADD.L    D0,D1
  1701.     SUBQ.L    #1,D1
  1702.     MOVE.L    D1,BLTDPTH-IOBASE(A0)
  1703.     MOVE.W    #$1DD8,BLTCON0-IOBASE(A0)
  1704.     MOVE.W    #$0002,BLTCON1-IOBASE(A0)
  1705.     MOVE.W    20(A1),BLTSIZE-IOBASE(A0) ;Set size and go
  1706.  
  1707.     MOVEA.L    (SP)+,A5
  1708.     RTS
  1709.  
  1710. ;======================================================================
  1711. ;Routine to scan for sync bytes at start of sector. These sync bytes
  1712. ; (A1A1, encoded as 44894489) may be shifted any number of bit positions
  1713. ;Inputs:
  1714. ;    D0 = Maximum number of encoded words to scan (2748/1660).
  1715. ;    A0 = Pointer to encoded data (at start of header).
  1716. ;Outputs:
  1717. ;    D0 = Number of bits of shift.
  1718. ;    A0 = Points to table entry before the entry that matches the
  1719. ;        sync byte.
  1720. ;
  1721. SUBRXO    MOVEM.L    D2-D4/A2,-(SP)
  1722.  
  1723.     MOVE.W    #$AAAA,D3    ;There are two possible patterns for
  1724.     MOVE.W    #$5555,D4    ; nulls depending on phase lock
  1725.  
  1726.     MOVEA.L    A0,A2        ;Point A2 to maximum scan position
  1727.     ADDA.L    D0,A2
  1728.  
  1729. LBB54    MOVE.W    (A0)+,D2    ;Get word from buffer
  1730.     CMP.W    D3,D2        ;Is it $AAAA?
  1731.     BEQ.S    LBB90        ;Branch if it is
  1732.     CMP.W    D4,D2        ;Is it $5555?
  1733.     BEQ.S    LBB68        ;Branch if it is
  1734.     CMPA.L    A0,A2        ;Loop if we haven't gone too far
  1735.     BHI.S    LBB54
  1736.  
  1737. LBB62    MOVEQ    #-1,D0        ;Indicate error
  1738.     MOVEA.L    D0,A0        ;A0 = -1
  1739.     BRA.S    LBB8A        ;Exit with error
  1740.  
  1741. ;Found a $5555:
  1742. LBB68    MOVEQ    #15,D0        ;Initialize counter for table entries
  1743.     LEA    TBLEVEN.L,A1    ;Point to table containing even bits
  1744.  
  1745. LBB70    CMPA.L    A0,A2        ;Have we scanned too far?
  1746.     BLS.S    LBB62        ;Branch if we have -- error exit
  1747.  
  1748.     MOVE.W    (A0)+,D1    ;Scan past nulls
  1749.     CMP.W    D2,D1
  1750.     BEQ.S    LBB70
  1751.  
  1752.     SUBQ.L    #2,A0        ;Back up a word
  1753.     MOVE.L    (A0),D1        ;Fetch long word from this location
  1754. LBB7E    CMP.L    (A1)+,D1    ;Compare it to entries in the table
  1755.     BEQ.S    LBB88        ;Exit loop if found
  1756.     SUBQ.L    #2,D0        ;Decrement counter
  1757.     BGE.S    LBB7E        ;Loop through table
  1758.     BRA.S    LBB54        ;Not found -- try again
  1759.  
  1760. LBB88    SUBQ.L    #4,A0        ;Adjust A0 to point to matching entry
  1761.  
  1762. LBB8A    MOVEM.L    (SP)+,D2-D4/A2
  1763.     RTS
  1764.  
  1765. LBB90    MOVEQ    #14,D0
  1766.     LEA    TBLODD.L,A1
  1767.     BRA.S    LBB70
  1768.  
  1769. ;These tables contain sync byte patterns for all possible bit shifts.
  1770. TBLEVEN    DC.L    $2244A244
  1771.     DC.L    $48912891
  1772.     DC.L    $52244A24
  1773.     DC.L    $54891289
  1774.     DC.L    $552244A2
  1775.     DC.L    $55489128
  1776.     DC.L    $5552244A
  1777.     DC.L    $55548912
  1778.  
  1779. TBLODD    DC.L    $91225122
  1780.     DC.L    $A4489448
  1781.     DC.L    $A9122512
  1782.     DC.L    $AA448944
  1783.     DC.L    $AA912251
  1784.     DC.L    $AAA44894
  1785.     DC.L    $AAA91225
  1786.     DC.L    $44894489    ;Normal unshifted position
  1787.  
  1788. ;----------------------------------------------------------------------
  1789. ;Decode word at A0 and return it in D0.
  1790. ;Inputs:
  1791. ;    A0 = Pointer to encoded buffer
  1792. ;    D2 = Number of bits to shift
  1793. ;
  1794. SUBRXR    MOVE.L    (A0)+,D0
  1795.     MOVE.W    (A0),D1
  1796.     MOVEQ    #16,D3
  1797.     SUB.L    D2,D3
  1798.     LSL.L    D3,D0        ;D0:= D0 *
  1799.     LSR.W    D2,D1
  1800.     OR.W    D1,D0
  1801.     RTS
  1802.  
  1803. ;----------------------------------------------------------------------
  1804. ;Routine to call the blitter handling routine.
  1805. ; Inputs:
  1806. ;    D0 = Byte offset into encoded buffer
  1807. ;    D1 = Index into sync table
  1808. ;    A2 = Pointer to max offset in buffer
  1809. ;
  1810. ;    A1 -->     0  -30
  1811. ;         4  -26  SUBRXT (not used)
  1812. ;         8  -22  D0
  1813. ;        12  -18  A0
  1814. ;        16  -14  A1 = pointer to max posn
  1815. ;        20  -10  BlitSize
  1816. ;        22   -8  Index into sync table
  1817. ;        24   -6  Data (word) at max scan posn
  1818. ;        26   -4  A3
  1819. ;    A2 -->    30    0
  1820. ;
  1821. ;
  1822. SUBRXS    LINK    A2,#-30        ;Reserve space for local variables
  1823.  
  1824.     MOVE.B    D1,-8(A2)
  1825.     TST.L    D1
  1826.     BEQ.S    LBE1A        ;Branch if no bit shift required
  1827.     ADDQ.L    #2,D0        ;Adjust byte offset
  1828. LBE1A
  1829.     MOVE.L    D0,D1
  1830.     ADDI.L    #63,D1
  1831.     ANDI.W    #$FFC0,D1
  1832.     ORI.W    #$0020,D1
  1833.     MOVE.W    D1,-10(A2)
  1834.  
  1835.     MOVEM.L    D0/A0-A1,-22(A2)
  1836.     MOVE.L    A3,-4(A2)
  1837.  
  1838.     LEA    IOBASE.L,A1
  1839. SXS20    MOVE.W    DMACONR-IOBASE(A1),D0    ;Wait for blitter not busy
  1840.     BTST    #14,D0
  1841.     BNE.S    SXS20
  1842.  
  1843.     MOVE.W    #$0040,INTREQ-IOBASE(A1) ;Clear blitter finished bit
  1844.  
  1845.     MOVEA.L    #$DFF000,A0
  1846.     LEA    -30(A2),A1    ;Point to blit structure
  1847.     BSR    SUBRXT
  1848.  
  1849.     LEA    IOBASE.L,A1
  1850. SXS30    MOVE.W    INTREQR-IOBASE(A1),D0    ;Wait for blitter finished
  1851.     BTST    #6,D0
  1852.     BEQ.S    SXS30
  1853.  
  1854.     LEA    -30(A2),A1    ;Point to blit structure
  1855.     TST.B    22(A1)        ;Test shift count
  1856.     BEQ.S    SXS40        ;Branch if no shift
  1857.     MOVEA.L    16(A1),A0    ;Get pointer to max position
  1858.     MOVE.W    24(A1),-2(A0)    ;Restore data
  1859. SXS40
  1860.     UNLK    A2        ;Release local variable space
  1861.     RTS
  1862.  
  1863. ;----------------------------------------------------------------------
  1864. ;Routine to handle the blitter.
  1865. ; Inputs:
  1866. ;    A0 = $DFF000
  1867. ;    A1 = Pointer to blit structure (node)
  1868. ;
  1869. SUBRXT    MOVE.L    A5,-(SP)    ;Save A5
  1870.  
  1871.     MOVEA.L    A1,A5        ;Save pointer to blit structure in A5
  1872.     BSR    SETBLIT        ;Set blitter registers
  1873.     MOVE.B    22(A5),D0    ;Get index into sync table
  1874.     MOVEQ    #12,D1        ;Move shift count into high nybble
  1875.     LSL.W    D1,D0
  1876.  
  1877.     MOVE.W    #$05CC,BLTCON0-IOBASE(A0) ;No shift, B = D
  1878.     MOVE.W    D0,BLTCON1-IOBASE(A0)    ;Set shift value for B source
  1879.  
  1880.     MOVEM.L    8(A5),D0-D1/A1    ;Restore registers from SUBRXS
  1881.     MOVE.L    D1,BLTBPTH-IOBASE(A0)
  1882.  
  1883.     TST.B    22(A5)        ;Get index into sync table
  1884.     BEQ.S    LBE94        ;Branch if shift count = 0
  1885.     SUBQ.L    #2,A1
  1886. LBE94
  1887.     MOVE.L    A1,BLTDPTH-IOBASE(A0)    ;Max scan positon
  1888.     MOVE.W    (A1),24(A5)
  1889.     MOVE.W    20(A5),BLTSIZE-IOBASE(A0) ;Set size and go
  1890.  
  1891.     MOVEA.L    (SP)+,A5    ;Restore A5
  1892.     RTS
  1893.  
  1894. ;----------------------------------------------------------------------
  1895. ;Set up blitter registers.
  1896. ; Inputs:
  1897. ;    A0 = $DFF000
  1898. ;
  1899. ;
  1900. SETBLIT    LEA    BLTAFWM-IOBASE(A0),A1    ;Set first word mask to all ones
  1901.     MOVE.L    #$FFFFFFFF,(A1)        ; i.e. no masking
  1902.  
  1903.     MOVEQ    #0,D0
  1904.     LEA    BLTBMOD-IOBASE(A0),A1
  1905.     MOVE.L    D0,(A1)+    ;BLTBMOD, BLTAMOD, modulo := 0
  1906.     MOVE.W    D0,(A1)+    ;BLTDMOD
  1907.  
  1908.     ADDQ.L    #8,A1
  1909.     MOVE.W    #$5555,(A1)    ;BLTCDAT
  1910.     RTS
  1911.  
  1912. ;======================================================================
  1913. ;Routine to delay at least D0 microseconds. (Be aware of interrupts and
  1914. ; DMA slowing things down. Also be aware that this may not work if a
  1915. ; faster processor is used.) This will work for up to 16 seconds of
  1916. ; delay.
  1917. ;
  1918. DELAY    MOVE.L    D2,-(SP)    ;Save D2
  1919.  
  1920.     MOVE.L    D0,D2        ;Get copy of the delay time in D2
  1921.     LSR.L    #8,D2        ;Divide it by 256
  1922. DLY10    MOVE.L    #256,D0        ;Set D0 to delay 256 us
  1923.  
  1924.     LSR.W    #1,D0        ;Adjust D0 for delay loop
  1925.     MOVE.L    D0,D1
  1926.     LSR.W    #1,D1
  1927.     ADD.L    D1,D0
  1928.     LSR.W    #2,D1
  1929.     SUB.L    D1,D0
  1930.     MOVE.W    D0,D1
  1931.     SWAP    D0
  1932.  
  1933. DLY20    DBF     D1,@        ;Kill 10 cycles * D1 / 6.7  (microsec)
  1934.     MOVE.W    #$FFFF,D1
  1935.     SUBQ.W    #1,D0
  1936.     BPL.S    DLY20
  1937.  
  1938.     DBF    D2,DLY10    ;Loop for each 256 us interval
  1939.  
  1940.     MOVE.L    (SP)+,D2    ;Restore D2
  1941.     RTS
  1942.  
  1943. ;----------------------------------------------------------------------
  1944. ;Routine to compute the "checksum" of encoded data.
  1945. ; Inputs:
  1946. ;    D1 = Number of bytes of encoded data
  1947. ;    A0 = Location of the bytes
  1948. ; Outputs:
  1949. ;    D0 = The 32-bit "checksum"
  1950. ;
  1951. DOCKSUM    MOVE.L    D2,-(SP)    ;Save D2
  1952.  
  1953.     LSR.W    #2,D1        ;Divide by 4 to get long words
  1954.     SUBQ.W    #1,D1        ;Compensate for DBF which includes 0
  1955.     MOVEQ    #0,D0        ;Initialize checksum
  1956.  
  1957. DOCK10    MOVE.L    (A0)+,D2    ;EOR the bits (parity style)
  1958.     EOR.L    D2,D0
  1959.     DBF     D1,DOCK10
  1960.  
  1961.     ANDI.L    #$55555555,D0    ;Mask off the MFM clock bits
  1962.  
  1963.     MOVE.L    (SP)+,D2    ;Restore D2
  1964.     RTS
  1965.  
  1966. END    EQU    @-1        ;ADDRESS OF END OF HANDLER
  1967.  
  1968. ;======================================================================
  1969. ;Hook this handler into the unit-handler tables
  1970. ;
  1971.     ORG    4 *UNTNUM +MAXTBL
  1972.     DC.L    3520
  1973.     DC.L    3520
  1974.  
  1975.     ORG    4 *UNTNUM +OFFTBL
  1976.     DC.L    0
  1977.     DC.L    0
  1978.  
  1979.     ORG    4 *UNTNUM +UNTTBL
  1980.     DC.L    FLOPHAN
  1981.     DC.L    FLOPHAN
  1982.  
  1983.     END
  1984.     3520
  1985.     DC.L    3520
  1986.  
  1987.     ORG    4 *U